﻿#include <stdio.h>
#include <stdlib.h>

#include <QPainter>
#include <QPaintEvent>
#include <QPen>
#include <QBrush>
#include <QImage>
#include <QTimeLine>
#include <QDebug>
#include <QAudio>
#include <QAudioOutput>
#include <QAudioBuffer>
#include <QIODevice>
#include <QThread>
//#include <QAudioDeviceInfo>

#include "TVPlayer.h"
#include "StreamDecodec.h"
#include "StreamEncodec.h"

extern "C" {

#include "libavutil/log.h"
#include "libavutil/avutil.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"

}

const int CONST_STREAM_TIMEOUT = 0x1388;
const int CONST_BUFFER_FRAME_COUNT = 0x05;

TVPlayer::TVPlayer(QWidget* parent /*= nullptr*/)
    : QWidget(parent)
    , m_pDecodec(nullptr)
    , m_pEncodec(nullptr)
    , m_pTimeLine(nullptr)
    , m_bStreamTimeout(false)
    , m_bVideoPlaying(false)
    , m_pAudioOutPut(nullptr)
    , m_AduioIO(nullptr)
    , m_nTimerId(0)
{
    init();
}

TVPlayer::~TVPlayer()
{
    stop();
    this->thread()->msleep(100);
}

void TVPlayer::setUrl(QString val)
{
    m_strUrl = val;
    if (m_pDecodec)
    {
        m_pDecodec->setUrl(m_strUrl);
    }
}

void TVPlayer::play()
{
    if (m_pDecodec && !m_strUrl.isEmpty())
    {
        m_bVideoPlaying = true;
        m_pDecodec->play();
        m_pTimeLine->start();
    }

}

void TVPlayer::stop()
{
    m_pDecodec->setExitRead(true);

    m_bVideoPlaying = false;
    m_pTimeLine->stop();
}

void TVPlayer::init()
{
    // 日志等级
    av_log_set_level(AV_LOG_DEBUG);
    //av_log(NULL, AV_LOG_DEBUG, "test.");
    // 注册所有
    av_register_all();

    // 编码器结构体
    // AVCodec;

    // 编码器上下文
    // AVCodecContext

    // 解码后的桢-未压缩的桢
    //AVFrame

    //结构体的分配和释放
    //av_frame_alloc();
    //av_frame_free();
    //avcodec_alloc_context3();
    //avcodec_free_context()

    // 解码步骤
    // 1.查找解码器
    //avcodec_find_decoder()
    // 2.打开解码器
    //avcodec_open2()
    // 3.解码
    //avcodec_decode_video2()
    // 4.绘制画面

    // 编码步骤
    // 1.查找编码器
    //avcodec_find_encoder_by_name()
    // 2.设备编码参数，并打开编码器
    // avcodec_alloc_context3() 创建编码器上下文
    //avcodec_open2()
    // 3.编码
    // avcodec_encode_video2()
    // 4.保存视频

    m_pDecodec = new StreamDecodec(this);
    m_pEncodec = new StreamEncodec(this);
    m_pTimeLine = new QTimeLine(CONST_STREAM_TIMEOUT, this);
    m_pTimeLine->setLoopCount(0);

    connect(m_pDecodec, SIGNAL(sigStreamView(QVariant)), this, SLOT(slotStreamRecvView(QVariant)));
    connect(m_pDecodec, SIGNAL(sigStreamAudio(QVariant)), this, SLOT(slotStreamAudio(QVariant)));
    connect(m_pTimeLine, SIGNAL(finished()), this, SLOT(slotStreamTimeout()));

    //startTimer(40);
}

void TVPlayer::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    if (m_bVideoPlaying)
    {
        if (m_bStreamTimeout || m_currentImage.isNull())
        {
            paintBlankFrame(&painter);
        }
        else
        {
            painter.drawImage(this->rect(), m_currentImage);
            m_pTimeLine->stop();
            m_pTimeLine->setCurrentTime(0);
            m_pTimeLine->start();
        }
    }
    else
    {
        paintBlankFrame(&painter);
    }

    QWidget::paintEvent(event);
}

void TVPlayer::paintBlankFrame(QPainter* painter)
{
    QPen pen(Qt::black);
    painter->setPen(pen);
    painter->setBrush(QBrush(Qt::black, Qt::SolidPattern));
    painter->drawRect(this->rect());

    pen.setColor(Qt::white);
    painter->setPen(pen);
    painter->setFont(QFont(QStringLiteral("楷体"), 128, 64));
    painter->drawText(this->rect(), Qt::AlignCenter, QStringLiteral("无信号"));
}

void TVPlayer::timerEvent(QTimerEvent* event)
{
    if (!m_queueStreamView.isEmpty())
    {
        QVariant varImage = m_queueStreamView.dequeue();
        if (!varImage.isNull())
        {
            QImage view = varImage.value<QImage>();

            m_currentImage = view;
        }
        
    }
    if (!m_queueStreamAudio.isEmpty())
    {
        //m_mutex.lock();
        if (m_pAudioOutPut)
        {
//             if (m_pAudioOutPut->state() == QAudio::IdleState)
//             {
//                 QVariant varAudio = m_queueStreamAudio.dequeue();
//                 QAudioBuffer buffer = varAudio.value<QAudioBuffer>();
//                 m_pAudioOutPut->setBufferSize(buffer.byteCount());
//                 m_AduioIO->write((const char *)buffer.constData(), buffer.byteCount());
//             }
            // 可写入字节数 大于本包的字节数 4096：本包字节数
            if (m_pAudioOutPut->bytesFree() > 4096)
            {
                QVariant varAudio = m_queueStreamAudio.dequeue();
                QAudioBuffer buffer = varAudio.value<QAudioBuffer>();
                //m_pAudioOutPut->setBufferSize(buffer.byteCount());

                int nSize = m_AduioIO->write((const char *)buffer.constData(), buffer.byteCount());
            }

//             qDebug() << "error info:" << m_AduioIO->errorString()
//                 << ", write size:" << nSize
//                 << ", buffer size:" << buffer.byteCount()
//                 << ", output error:" << m_pAudioOutPut->error()
//                 << ", frame count:" << buffer.frameCount()
//                 << ", byte count:" << buffer.byteCount()
//                 << ", sample count:" << buffer.sampleCount();
        }
        else
        {
            QVariant varAudio = m_queueStreamAudio.dequeue();
            if (!varAudio.isNull())
            {
                QAudioBuffer buffer = varAudio.value<QAudioBuffer>();

                //m_pDeviceInfo = new QAudioDeviceInfo(QAudioDeviceInfo::defaultOutputDevice());


                m_pAudioOutPut = new QAudioOutput(buffer.format(), this);
                //m_pAudioOutPut->setBufferSize(buffer.byteCount());
                m_AduioIO = m_pAudioOutPut->start();

                m_AduioIO->write((const char *)buffer.constData(), buffer.byteCount());
            }
        }
        //m_mutex.unlock();
    }

    this->update();

    QWidget::timerEvent(event);
}

void TVPlayer::slotStreamRecvView(QVariant view)
{
    if (m_queueStreamView.size() >= CONST_BUFFER_FRAME_COUNT)
    {
        m_queueStreamView.dequeue();
        m_queueStreamView.enqueue(view);
    }
    else
    {
        m_queueStreamView.enqueue(view);
    }

    if (m_queueStreamView.size() >= CONST_BUFFER_FRAME_COUNT)
    {
        m_nTimerId = startTimer(40);
    }
    else
    {
        //killTimer(m_nTimerId);
    }
    m_bStreamTimeout = false;
}

void TVPlayer::slotStreamAudio(QVariant audio)
{
    if (m_queueStreamAudio.size() > CONST_BUFFER_FRAME_COUNT)
    {
        m_queueStreamAudio.dequeue();
        m_queueStreamAudio.enqueue(audio);
    }
    else
    {
        m_queueStreamAudio.enqueue(audio);
    }
}

void TVPlayer::slotStreamTimeout()
{
    m_bStreamTimeout = true;

}


